#include <ALEstd.h>
#include <EventManagerImpl.h>
#include <CTimer.h>

EventManager::EventManager(const char* pName, bool global)
	: IEventManager(pName, global)
{
	m_activeQueue = 0;
}

EventManager::~EventManager()
{

}

bool EventManager::VAddListener(const EventListenerDelegate& eventDelegate, const EventType& type)
{
	EventListenerList& eventListenerList = m_eventListeners[type];
	for (auto it = eventListenerList.begin(); it != eventListenerList.end(); ++it)
	{
		if(eventDelegate == (*it))
		{
			return false;
		}
	}
	eventListenerList.push_back(eventDelegate);

	return true;
}

bool EventManager::VRemoveListener(const EventListenerDelegate& eventDelegate, const EventType& type)
{
	bool success = false;

	auto findIt = m_eventListeners.find(type);
	{
		if(findIt != m_eventListeners.end())
		{
			EventListenerList& listeners = findIt->second;
			for( auto it = listeners.begin(); it != listeners.end(); ++it)
			{
				if (eventDelegate == (*it))
				{
					listeners.erase(it);
					success = true;
					break;
				}
			}
		}
	}

	return success;
}

bool EventManager::VTriggerEvent(const IEventPtr& pEvent) const
{
	bool processed = false;

	auto findIt = m_eventListeners.find(pEvent->VGetEventType());
	if (findIt != m_eventListeners.end())
	{
		const EventListenerList& eventListenerList = findIt->second;
		for (EventListenerList::const_iterator it = eventListenerList.begin(); it != eventListenerList.end(); ++it)
		{
			EventListenerDelegate listener = (*it);
			listener(pEvent);
			processed = true;
		}
	}

	return processed;
}

bool EventManager::VQueueEvent(const IEventPtr& pEvent)
{
	if(!pEvent)
	{
		return false;
	}

	auto findIt = m_eventListeners.find(pEvent->VGetEventType());
	if (findIt != m_eventListeners.end())
	{
		m_queues[m_activeQueue].push_back(pEvent);
		return true;
	}
	else
	{
		return false;
	}
}

bool EventManager::VAbortEvent(const EventType& inType, bool all)
{
	bool success = false;
	EventListenerMap::iterator findIt = m_eventListeners.find(inType);

	if(findIt != m_eventListeners.end())
	{
		EventQueue& eventQueue = m_queues[m_activeQueue];
		auto it = eventQueue.begin();
		while (it != eventQueue.end())
		{
			auto thisIt = it;
			++it;

			if ((*thisIt)->VGetEventType() == inType)
			{
				eventQueue.erase(thisIt);
				success = true;
				if (!all)
					break;
			}
		}
	}

	return success;
}

bool EventManager::VUpdate(unsigned long maxMillis)
{
	CTimer timer;
	timer.reset();

	int queueToProcess = m_activeQueue;
	m_activeQueue = (m_activeQueue +1 ) % EVENTMANAGER_NUM_QUEUES;
	m_queues[m_activeQueue].clear();

	while (!m_queues[queueToProcess].empty())
	{
		IEventPtr pEvent = m_queues[queueToProcess].front();
		m_queues[queueToProcess].pop_front();

		const EventType& eventType = pEvent->VGetEventType();

		auto findIt = m_eventListeners.find(eventType);
		if(findIt != m_eventListeners.end())
		{
			const EventListenerList& eventListeners = findIt->second;
			for (auto it = eventListeners.begin(); it != eventListeners.end(); ++it)
			{
				EventListenerDelegate listener = (*it);
				listener(pEvent);
			}
		}
		if ( maxMillis != IEventManager::kINFINITE && timer.stopwatch(maxMillis))
		{
			break;
		}
	}

	bool queueFlushed = (m_queues[queueToProcess].empty());
	if (!queueFlushed)
	{
		while (!m_queues[queueToProcess].empty())
		{
			IEventPtr pEvent = m_queues[queueToProcess].back();
			m_queues[queueToProcess].pop_back();
			m_queues[m_activeQueue].push_front(pEvent);
		}
	}

	return queueFlushed;
}
